版本信息
应用系统信息
- Spring(4.3.18.RELEASE) + Spring MVC(4.3.18.RELEASE) + Mybatis(3.4.6)
- Shiro(shiro-web 1.2.3 + shiro+spring 1.2.3 + shiro+cas 1.2.3)
- 操作系统:Ubuntu14.04 LTS amd64
- Tomcat 8.5.39
- Nginx 1.4.6
- JDK 1.8.0_181
统一认证平台系统信息
- 由于集成的是学校的统一认证平台,尚不清楚是具体的信息,只提供了http的域名
- 使用了 Shiro + CAS 实现了单点登录
背景
最近在做一个基于NB-IoT的物联网智能门锁项目,后台使用SSM实现的一个统一的智能门锁管理系统,一开始有一套自己的用户,密码机制。
需求
- 应用系统需要集成统一认证平台,实现单点登录
- 微信小程序实现单点登录统一认证平台,然后访问系统,获取信息
问题
- 摒弃应用系统的原有的一套密码机制,实现单点登录(卧槽没有单点登录的经验啊,咋弄?)
- 微信小程序统一认证授权,一般只有微信呀、微博等的授权机制(自建统一认证平台,咋实现统一认证登录?)
- 微信小程序发布时需要有HTTPS的域名(学校提供的只有HTTP的,又不能增加HTTPS,咋弄?)
头大、头大、头大
过程
没办法,硬着头皮也得来呀,心里一万个难受。
应用系统集成统一认证平台
- 集成学校统一认证平台的提供了文档,按照上面的来配置,改了Web.xml,体检了一些监听器和过滤器,重启系统,跳转,卧槽可以了呀?登录。。。。。。失败。。。。。。没反应?
- 然后又是疯狂的看文档,跑学校提供的测试Demo,没错啊,就这样,就这样配的啊,开始自我怀疑了。。。。。。
- 查资料,各种Google、Baidu,突然发现Shiro+CAS实现单点登录? 文档中提到了也是CAS的???,这不是一样的吗?
- 然后按照网上提供的教程,重写shiro的配置文件,原来应用系统提供了ShiroDBrealm的认证,现在是ShiroCasrealm的认证方式。配完之后发现,没有统一认证服务器啊?咋办?学校那边在后台添加了我的这认证的那个域名,本机没法弄啊,神奇1的Github派上用场了,弄个测试服务器啊(^_^) spring-shiro-cas
- 放在tomcat里面,在本机上其他端口跑起来,应用系统配置写好对应的配置文件跑起来。登录成功。
下面是Shiro的配置文件
1 | shiro.loginUrl=http://192.168.10.185:8081/cas/login?service=http://192.168.10.185:8080/cas |
spring-shiro-cas.xml
1 |
|
替换成学校的统一认证接口,部署发现可以了。
微信小程序集成统一认证平台
查阅文档,小程序好像没有集成第三方认证系统的能力啊?貌似自由微信、微博啥的统一授权的,自建的第三方系统咋集成啊
小程序使用的是DCloud公司的uni-app开发的,在微信官方文档中有一种方式可以打开网页,使用web-view,咦。。。。。。好像发现新大陆了。
参考教程:在web-view加载的本地及远程HTML中调用uni的API及网页和vue页面通讯
这种方式可以需要修改服务端,添加页面,同时也需要改动微信微信小程序端的逻辑,实现web-view网页与小程序内的应用的通信。可行!
下面是我在微信小程序端的逻辑。
1 | // login.vue |
1 | // ids.vue |
服务端的返回的页面
1 |
|
这样一套下来就能实现登录、跳转、返回了。感觉还不错,突然想到,使用web-view需要有业务域名啊?还需要是https的,咋办?
业务域名好办,使用公司信息注册一下,https呢?在和学校的信息处沟通后发现,他们没法改添加https,哇咔咔,开始停工了。
老板开始问,除了小程序还能使用h5吗?,我说可以,但是不能使用蓝牙开门。。。。。。h5+呢?h5+是做APP的,咱们不能小程序,只有小程序了呀~~~
经过一两天的折腾后,老板问了下别人,有个技术说可以使用nginx反向代理啊或者弄个二级域名?想想自己的域名就是学校分配的二级域名,哪还有别的二级域名?nginx反向代理,使用https代理http?嗯~好像可行,一语惊醒。就这么搞,第二天开始弄。
卸载原来的Apache,安装Nginx,添加反向代理,👌了,这么简单吗?使用我系统的Chrome(macOS)、IPhone登录一下,我艹这么简单?高兴的说解决了,然后对旁边的狗振说,你登一下(Windows Chrome)。。。BUG发生了,WTF登不上。再用我电脑的FireFox和Safari登录,没问题啊,又换用彭狗子的Chrome(Windows)、Android登录,登不上。😔彻底心碎了,然后开始各种查。问于狗子、金涛、学校的技术人员,都没遇见过。
然后开始分析问题
登录的处理过程是,首先浏览器通过https链接匹配访问到应用系统,发现该用户没有登录,shiro拦截请求,并重定向到配置的统一认证服务器上,要求输入用户名和密码,登录成功后携带ticket票据到应用系统,应用系统不知道该票据是否有效,然后又发送请求到认证服务器,请求验证票据,验证成功后,回到应用系统完成登录、授权等逻辑。
通过登录失败的例子发现,客户端请求登录跳转到统一认证服务器上、说明能够通过反向代理进入到统一认证服务器,知识post过去,服务器没能正确的处理响应,返回ticket,而是登录没成功又重定向到了登录界面。一开始以为是nginx的反向代理没处理好,于是改源码,前面加一个字符,发现可以登录,难道是服务端的问题??不存在啊,加完字符后发现,不行呀,这太麻烦了,所有的静态文件、请求的路径都需要加上前缀,然后放弃了。继续测,要不在nginx那端做一下判断,看到底是否进错了匹配路径?,于是加上了\$uri 和 \$request_method 判断,结构发现没有啊,说明POST请求确实到了统一认证服务器,但返回了不是预期的结果。此时已经是今天第五天了。
上午突然想想到底为啥有的浏览器成功,有的浏览器失败呢,于是分析HTTP请求。首先分析了FireFox的登录成功的请求。
初次访问系统的时候系统在cookie中放置了一个JSESSIONID
随后浏览器Get重定向的连接访问统一认证平台,同时设置了一个新的JSESSIONID,这个JESSIONID是由统一认证平台设置的,由统一认证平台系统识别。
在请求中发现在请求的style.css文件里面又重新Get请求/login,使用了上图幅👆的JESSIONID,服务端并且响应了。
随后在后面的请求中请求了favicon.ico图标,这个图标是统一平台的图标,因此系统又返回了一个JSESSIONID,这个是Nginx的配置问题,这个图标的根路径没有匹配进去,这导致了这个JESSIONID是应用系统返回的,于是you重定向到统一认证平台了。
然后填写用户名和密码,发送POST数据,发现登录失败,在请求中发现系统返回了一个新的JESSIONID,这个新的JESSIONID是被统一认证平台识别。
然后再次填写用户名和密码,发送POST请求,发现登录成功,系统返回了票据,随后就登陆成功了,同时再请求中请求的JESSIONID是上面👆的JESSIONID
通过上面的请求发现,这个JESSIONID是被两个系统来回切换的,在登录成功后发现应用系统又设置了新的JESSIONID。
分析完了FireFox的请求,我们来分析一下Chrome的登录请求。分析一下Windows的Chrome的登录请求。
第一次请求访问应用系统返回一个JESSIONID
然后重定向到认证服务请,请求返回一个JESSIONID
然后在style.css中有请求了/login,使用上面👆的JESSIONID
然后请求了favicon.ico文件,跳转到应用系统返回了应用系统的JESSIONID
再重定向到认证服务器,返回认真服务器新的JESSIONID
使用新的JESSIONID发送POST请求,理论上JESSIONID是认证服务器能够是别的为什么不可以呢?
其实这里有一个错误,但这个错误现在不知道为什么不能重现了,当时发现的错误是,Chrome里面的Cookie里面设置了两个JESSIONID,理论上说只可以存在一个key,为什么会有两个key呢?POST过去含有两个JESSIONID,服务端肯定会报错的,因此可以判定是由于两个JESSIONID导致了会话之间出现了问题,服务器无法正常识别,因此改动了一下自己应用系统的shiro的Cookie名称。
1 | <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> |
更新(2019年10月25日 21:34)
在上面的分析中我们发现由于没有在nginx里面配置对统一认证服务器里面的/favicon.ico的匹配,导致当在请求该资源的时候,跳转到咱们的应用服务器,从而无法登陆,随后我在nginx上加了对favicon.ico的匹配规则,再吃使用未修改前的代码,使用不同操作系统的浏览器进行登录,发现均可以登录。唯一的不同之处是,用户在第一次访问应用服务器的时候,应用服务器返回的JESSIONID失效了,应为当认证服务器返回了JESSIONID就替换了原有的JESSIONID,当登录成功之后,应用服务器返回了新的JESSIONID,因此浪费了一次JESSIONID,从会话的角度讲,我觉着,这是一次完整的会话,只是涉及了两个不同应用程序不同域之间的交互,我上面的修改方式我觉着还是有必要的。
参考文章
- SpringMVC + Shiro 集成 CAS
- Cas单点登录及spring集成shiro-cas
- spring-shiro-cas
- 在web-view加载的本地及远程HTML中调用uni的API及网页和vue页面通讯
总结
通过这次这么长时间的尝试,修改,我也是收获很多,更重要的是要学会处理发生的问题,如何去分析,去解决,找到问题是关键。